package com.baofu.paycore.service;

import com.baofu.paycore.biz.model.PayResBO;
import com.baofu.paycore.biz.paycore.handler.impl.RefundHandler;
import com.baofu.paycore.common.utils.ExceptionUtil;
import com.baofu.paycore.manager.model.RefundBO;
import com.baofu.paycore.manager.storer.RefundOrderRepository;
import com.baofu.paycore.service.converter.BO2DTOConverter;
import com.baofu.paycore.service.facade.RefundServiceFacade;
import com.baofu.paycore.service.facade.model.PayResDTO;
import com.baofu.paycore.service.facade.model.refund.req.RefundReqDTO;
import com.baofu.paycore.service.factory.impl.RefundFactoryImpl;
import com.baofu.paycore.service.validate.impl.refund.RefundValidate;
import com.system.commons.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.slf4j.helpers.SystemMarker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

/**
 * 退款服务接口
 *
 * <p>
 *     退款接口服务
 * </p>
 * User: kwl Date: 2016/6/3 ProjectName: paycore Version: 5.0.0
 */
@Slf4j
@Service
public class RefundService implements RefundServiceFacade {

    /**
     * 退款参数校验服务
     */
    @Autowired
    private RefundValidate refundValidate;

    /**
     * 退款单构建工厂类
     */
    @Autowired
    private RefundFactoryImpl refundFactoryImpl;

    /**
     * 退款处理服务
     */
    @Autowired
    private RefundHandler refundHandler;

    /**
     * 退款订单处理
     */
    @Autowired
    private RefundOrderRepository refundOrderRepository;

    /**
     * spring事物模版
     */
    @Autowired
    private TransactionTemplate transactionTemplate;

    /**
     * 退款接口服务
     *
     * <p>
     * 交易退款金额 = 退款总金额 - 收手续费金额 - 退手续费金额
     * refundAmt = amt - freeAmt = refundFreeAmt
     * </p>
     *
     * @param refundReqDTO     退款请求参数
     * @param traceLogId       日志ID
     * @return                 退款返回结果
     *                         response.isSuccess()标示方法的远程调用状态，方法实际执行结果从result 取值
     */
    @Override
    public Result<PayResDTO> refund(RefundReqDTO refundReqDTO, String traceLogId) {
        Result<PayResDTO> result = null;
        long startTime = System.currentTimeMillis();
        boolean flag = false;

        try{
            MDC.put(SystemMarker.TRACE_LOG_ID,traceLogId);

            log.info("退款接口请求参数,refundDTO:{}", refundReqDTO);
            flag = refundValidate.lock(refundReqDTO);

            //1、请求对象参数校验
            refundValidate.paramsValidate(refundReqDTO);
            refundValidate.validateRefund(refundReqDTO.getAmt(), refundReqDTO.getRefundFeeAmt(),
                    refundReqDTO.getFreeAmt());

            //2、幂等性校验
            RefundBO idempotent = refundOrderRepository.checkIdempotent(refundReqDTO.getRequestBizNo(),
                    refundReqDTO.getRequestOrderNo(),refundReqDTO.getRequestSystem());
            if(null != idempotent) {
                return new Result<>(BO2DTOConverter.getRefundResDTOByRefundBO(idempotent));
            }

            //3、支付订单对象构建处理流程
            RefundBO refundBO = buildProcess(refundReqDTO);
            refundBO.setTradeLogId(traceLogId);
            //4、退款流程处理
            PayResBO payResBO = refundHandler.refund(refundBO);

            //5、退款返回结果封装
            result = new Result<>(BO2DTOConverter.getRefundResDTOByPayResBO(payResBO));

        } catch (Exception e) {

            log.error("统一支付退款交易失败, error:{}",e);
            result = ExceptionUtil.doExceptionService(e,PayResDTO.class);
        } finally {

            log.info("退款接口返回结果,time:{},RESULT:{}", System.currentTimeMillis() - startTime,result);
            refundValidate.release(refundReqDTO,flag);
            MDC.clear();
        }
        return result;
    }

    /**
     * 支付订单对象构建处理流程
     *
     * @param refundReqDTO    退款请求DTO参数
     * @return                退款请求BO参数
     */
    private RefundBO buildProcess(RefundReqDTO refundReqDTO){

        return transactionTemplate.execute(status -> {

            //1、退款请求对象转换
            RefundBO refundBO = refundFactoryImpl.build(refundReqDTO);

            //2、退款相关信息落地
            refundOrderRepository.addOrder(refundBO);

            return refundBO;
        });
    }

}
